#include "AtomDemo.h"


bool AtomDemo::Init_()
{

    PrepareRecordFile();

    if(PrepareAndCreateMultiThread() == false)
    {
        std::cout<<"Init MultiThread Failed!"<<endl;
        return false;
    }

    m_nState = DEMO_STATUS_INITIALIZED;


    capture1.open(0);
    if (capture1.isOpened)
    {
        cout<<"video is open"<<endl;
    }else
    {
        return false
    }

    capture2.open(1);
    if (capture2.isOpened)
    {
        cout<<"video is open"<<endl;
    }else
    {
        return false
    }




    return true;

}

bool AtomDemo::PrepareRecordFile()
{
//check the log filename in floder. then creat the newest filename to record the  system data
    for (int i = 0;; ++i)
        {
            ostringstream ostr;
            ostr << "log/log_";
            ostr << setfill('0') << setw(4) << i;
            ostr << ".txt";
            ifstream ifs(ostr.str());
            if (!ifs.is_open())
            {
                m_curFileNo = i;
                m_OF_rec.open(ostr.str());
                stream_file_table[&m_OF_rec] = ostr.str();
                break;
            }
            else
                ifs.close();
        }
//write the date on logfile
    SaveDateRecord(m_OF_rec);

    return true;
}

void AtomDemo::SaveDateRecord(ofstream& m_OF_rec)
{
	time_t now = time(0);
	struct tm tstruct;
	char buf[80];
	tstruct = *localtime(&now);
	strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
    m_OF_rec << buf << endl << endl;
}

bool AtomDemo::PrepareAndCreateMultiThread()
{
    //init the eventlist bTimed=1 means this is a time event

    for (int i = 0; i < EVENT_NCOUNT; ++i)
    {
        bTimed[i] = 1;
    }
    bTimed[0] = bTimed[1] = 0;

    if (!Demo_Event_List.Initialize(EVENT_NCOUNT, bTimed, waitTime))
    {
        return false;
    }

    int iCount = 0;
    while (iCount < THREAD_CREATION_MAX_TRIALS)
    {
        if (0 == pthread_create(&m_THREAD_1, NULL, &Thread_1, (void*) this))
        {
            cout << "SUCCEED creating the THREAD_1!!!\n";
            break;
        }
        ++iCount;
        if (iCount == THREAD_CREATION_MAX_TRIALS)
        {
            cout << "ERROR creating the THREAD_1!!!\n";
            return false;
        }
    }

    iCount = 0;
    while (iCount < THREAD_CREATION_MAX_TRIALS)
    {
        if (0 == pthread_create(&m_THREAD_2, NULL, &Thread_2, (void*) this))
        {
            cout << " SUCCEED creating the THREAD_2!!!\n";
            break;
        }
        ++iCount;

        if (iCount == THREAD_CREATION_MAX_TRIALS)
        {
        cout << "ERROR creating the THREAD_2!!!\n";
        return false;
        }
    }
    return true;
}

void* AtomDemo::Thread_1(void* lpPara)
{
    AtomDemo* pThis = (AtomDemo*)lpPara;
    while (1)
    {
        if (pThis->Atom_Event_List.Wait(EVENT_NUM_TERMINATE_THREAD_1))
            break;


    }
}

void* AtomDemo::Thread_2(void* lpPara)
{
    AtomDemo* pThis = (AtomDemo*)lpPara;
    while (1)
    {
        if (pThis->Atom_Event_List.Wait(EVENT_NUM_TERMINATE_THREAD_2))
            break;


    }
}

void AtomDemo::EndMultiThreads()
{
    if (m_THREAD_1)
    {
        Atom_Event_List.Set(EVENT_NUM_TERMINATE_MAP);
    }

    if (m_THREAD_1)
    {
        Atom_Event_List.Set(EVENT_NUM_TERMINATE_REMOTE);
    }

    Atom_Event_List.CloseAll();
}


int AtomDemo::KeyTest(void)
{
    struct termios oldt,newt;
    int ch;
    int oldf;

    //back old configuration, set the standard input into non-blocking mode
    tcgetattr(STDIN_FILENO,&oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO,TCSANOW,&newt);
    oldf = fcntl(STDIN_FILENO,F_GETFL,0);
    fcntl(STDIN_FILENO,F_SETFL,oldf | O_NONBLOCK);

    //get char from input with non-blocling mode
    ch = getchar();

    //restore old configurtion
    tcsetattr(STDIN_FILENO,TCSANOW,&oldt);
    fcntl(STDIN_FILENO,F_SETFL,oldf);

    if(ch != EOF)
    {
        putchar(0x08);
        return ch;
    }
    return 0;

}

void AtomDemo::ConvertKeyToSignal(char userKey)
{

    if(userKey == 27)
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_TERMINATE);
    }
    else if(userKey == 'q' || userKey == 'Q')
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_TERMINATE);
    }
    else if(userKey == '1')
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_1);
    }
    else if(userKey == '2')
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_2);
    }
    else if(userKey == '3')
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_3);
    }
    else if(userKey == '4' )
    {
        Demo_Event_List.Set(EVENT_NUM_REQUEST_4);
    }
    //...


}

void AtomDemo::EventListLoopHandle(BYTE& commandType)
{
    //eventlist loop.   handl the corresponding event
    if (Demo_Event_List.Wait(EVENT_NUM_REQUEST_TERMINATE))
    {
        cout << "Command: TERMINATE...\n";
        commandType = EVENT_NUM_REQUEST_TERMINATE;
    }
    else if (Demo_Event_List.Wait(EVENT_NUM_TERMINATE_THREAD_1))
    {
        cout << "Command: TERMINATE THREAD_1...\n";
        commandType = EVENT_NUM_TERMINATE_THREAD_1;
    }
    else if (Demo_Event_List.Wait(EVENT_NUM_TERMINATE_THREAD_2))
    {
        cout << "Command: TERMINATE THREAD_2...\n";
        commandType = EVENT_NUM_TERMINATE_THREAD_2;
    }
    else if (Demo_Event_List.Wait(EVENT_NUM_REQUEST_1))
    {
        cout << "Command  REQUEST_1 ...\n";
        commandType = EVENT_NUM_REQUEST_1;
    }

}

bool AtomDemo::MainTask()
{
    while(1)
    {
        m_timerHQ_t1 = high_resolution_clock::now();
        //------------------------------------------------------------
        //---0-respond to user operation -----------------------------
        //------------------------------------------------------------
        char c =  KeyTest();
        ConvertKeyToSignal(c);

        BYTE commandType = 0;
        EventListLoopHandle(commandType);
        //means event request terminate
        if(commandType == EVENT_NUM_REQUEST_TERMINATE) break;
        //------------------------------------------------------------
        //---1-demo run -----------------------------
        //------------------------------------------------------------
/*
        av_read_frame(pInputFormatContext, &InPack);
		len = avcodec_decode_video2(pInputCodecContext, &OutFrame, &nComplete, &InPack);//解码视频
		if (nComplete>0)
		{	
			if (GetMessage(&msg, NULL, 0, 0))
			{
				switch(msg.message)
				{
                    case MY_MSG_DECODE:
                        sws_scale(m_pSwsContext,OutFrame.data,OutFrame.linesize, 0,OutFrame.height,dst->data,dst->linesize);//转换图片大小
                        memcpy(littleframe.data,dst->data[0], 640*480);  //以下将ffmpeg的yuv数据存到opencv的mat类型中。即opencv存储的yuv数据
                        memcpy(littleframe.data+640*480,dst->data[1], 640*480/4);  
                        memcpy(littleframe.data+640*480*5/4,dst->data[2], 640*480/4); 
                        SetEvent(hEncodeEvent);
                        break;
				}
			}
 
		}
		av_free_packet(&InPack);

        cv::cvtColor(littleframe, littlergb,CV_YUV2BGR_I420); //yuv转rgb
        cv::cvtColor(bigframe, bigrgb,CV_YUV2BGR_I420); //yuv转rgb 

        Mat roi(bigrgb,Rect(0,0,640,480));//大图上设置敏感区  
        littlergb.copyTo(roi);  //把小图拷贝过去 

        Mat outframe;  
        cv::cvtColor(bigrgb, outframe,CV_BGR2YUV_I420); //rgb到yuv 
*/

        capture1>>frame1; //取出一帧
        if (!frame1.empty())
        {
            cv::imshow("camera1", frame1);   //在窗口显示
        }

        capture2>>frame2; //取出一帧
        if (!frame2.empty())
        {
            cv::imshow("camera2", frame2);   //在窗口显示
        }

        if (!frame1.empty() && !frame2.empty())
        {

            cv::Mat resize_image, roi_image;
            /*CV_EXPORTS_W void resize( InputArray src, OutputArray dst,
                              Size dsize, double fx = 0, double fy = 0,
                              int interpolation = INTER_LINEAR );*/

            roi_image = frame2;
            resize(frame1, resize_image, Size(frame1.cols/2, frame1.rows/2));
            //resize(tmp_image, dst_image2, Size(), 0.5, 0.5);

            Mat roi(roi_image,Rect(0,0,resize_image.cols,resize_image.rows));//大图上设置敏感区  
            resize_image.copyTo(roi);  //把小图拷贝过去 

            cv::imshow("roi_image", roi_image);


        }
        



        m_timerHQ_t2 = chrono::high_resolution_clock::now();
        double MainTask_Interval_in_MS = chrono::duration_cast<chrono::nanoseconds>
            (m_timerHQ_t2 - m_timerHQ_t1).count() / (1e6);
        cout<< "MainTask_Interval_in_MS:"<<MainTask_Interval_in_MS<<endl;

        cv::waitKey(30);
    }

    ExitMainTask(1);
    cout << "MainTask() finished.\n";
    return true;

}

bool AtomDemo::ExitMainTask(BYTE bTerminate)
{
    return true;
}

AtomDemo::AtomDemo()
{
    
    Init_();

    if(m_nState != DEMO_STATUS_INITIALIZED)
    {
        std::cout<<"System Init Failed! Exiting... "<<std::endl;
        return;
    }

    std::cout<<"System Init ! "<<std::endl;
    m_nState = DEMO_STATUS_RUN;
    MainTask();

}

AtomDemo::~AtomDemo()
{
        
    EndMultiThreads();
#ifdef TEST_MODE_FILE_RECORD
    if (m_OF_rec.is_open())
    {
        m_OF_rec.close();
    }
    std::cout<<"close flie: "<<stream_file_table[&m_OF_rec]<<std::endl;
#endif 
}